﻿using System;
using GeoAPI.Geometries;
using NetTopologySuite.Geometries.Utilities;

namespace NetTopologySuite.Simplify
{
	public class VWSimplifier
	{
		public static IGeometry Simplify(IGeometry geom, double distanceTolerance)
		{
			return new VWSimplifier(geom)
			{
				DistanceTolerance = distanceTolerance
			}.GetResultGeometry();
		}

		public VWSimplifier(IGeometry inputGeom)
		{
			this._inputGeom = inputGeom;
		}

		public double DistanceTolerance
		{
			get
			{
				return this._distanceTolerance;
			}
			set
			{
				if (value < 0.0)
				{
					throw new ArgumentException("Tolerance must be non-negative");
				}
				this._distanceTolerance = value;
			}
		}

		public bool IsEnsureValidTopology
		{
			get
			{
				return this._isEnsureValidTopology;
			}
			set
			{
				this._isEnsureValidTopology = value;
			}
		}

		public IGeometry GetResultGeometry()
		{
			if (this._inputGeom.IsEmpty)
			{
				return (IGeometry)this._inputGeom.Clone();
			}
			return new VWSimplifier.VWTransformer(this.IsEnsureValidTopology, this.DistanceTolerance).Transform(this._inputGeom);
		}

		private readonly IGeometry _inputGeom;

		private double _distanceTolerance;

		private bool _isEnsureValidTopology = true;

		private class VWTransformer : GeometryTransformer
		{
			public VWTransformer(bool isEnsureValidTopology, double distanceTolerance)
			{
				this._isEnsureValidTopology = isEnsureValidTopology;
				this._distanceTolerance = distanceTolerance;
			}

			protected override ICoordinateSequence TransformCoordinates(ICoordinateSequence coords, IGeometry parent)
			{
				Coordinate[] array = coords.ToCoordinateArray();
				Coordinate[] coordinates;
				if (array.Length == 0)
				{
					coordinates = new Coordinate[0];
				}
				else
				{
					coordinates = VWLineSimplifier.Simplify(array, this._distanceTolerance);
				}
				return this.Factory.CoordinateSequenceFactory.Create(coordinates);
			}

			protected override IGeometry TransformPolygon(IPolygon geom, IGeometry parent)
			{
				if (geom.IsEmpty)
				{
					return null;
				}
				IGeometry geometry = base.TransformPolygon(geom, parent);
				if (parent is IMultiPolygon)
				{
					return geometry;
				}
				return this.CreateValidArea(geometry);
			}

			protected override IGeometry TransformLinearRing(ILinearRing geom, IGeometry parent)
			{
				bool flag = parent is IPolygon;
				IGeometry geometry = base.TransformLinearRing(geom, parent);
				if (flag && !(geometry is ILinearRing))
				{
					return null;
				}
				return geometry;
			}

			protected override IGeometry TransformMultiPolygon(IMultiPolygon geom, IGeometry parent)
			{
				IGeometry rawAreaGeom = base.TransformMultiPolygon(geom, parent);
				return this.CreateValidArea(rawAreaGeom);
			}

			private IGeometry CreateValidArea(IGeometry rawAreaGeom)
			{
				if (!this._isEnsureValidTopology)
				{
					return rawAreaGeom;
				}
				return rawAreaGeom.Buffer(0.0);
			}

			private readonly bool _isEnsureValidTopology = true;

			private readonly double _distanceTolerance;
		}
	}
}
